/*
quu..__
 $$$b  `---.__
  "$$b        `--.                          ___.---uuudP
   `$$b           `.__.------.__     __.---'      $$$$"              .
     "$b          -'            `-.-'            $$$"              .'|
       ".                                       d$"             _.'  |
         `.   /                              ..."             .'     |
           `./                           ..::-'            _.'       |
            /                         .:::-'            .-'         .'
           :                          ::''\          _.'            |
          .' .-.             .-.           `.      .'               |
          : /'$$|           .@"$\           `.   .'              _.-'
         .'|$u$$|          |$$,$$|           |  <            _.-'
         | `:$$:'          :$$$$$:           `.  `.       .-'
         :                  `"--'             |    `-.     \
        :##.       ==             .###.       `.      `.    `\
        |##:                      :###:        |        >     >
        |#'     `..'`..'          `###'        x:      /     /
         \                                   xXX|     /    ./
          \                                xXXX'|    /   ./
          /`-.                                  `.  /   /
         :    `-  ...........,                   | /  .'
         |         ``:::::::'       .            |<    `.
         |             ```          |           x| \ `.:``.
         |                         .'    /'   xXX|  `:`M`M':.
         |    |                    ;    /:' xXXX'|  -'MMMMM:'
         `.  .'                   :    /:'       |-'MMMM.-'
          |  |                   .'   /'        .'MMM.-'
          `'`'                   :  ,'          |MMM<
            |                     `'            |tbap\
             \                                  :MM.-'
              \                 |              .''
               \.               `.            /
                /     .:::::::.. :           /
               |     .:::::::::::`.         /
               |   .:::------------\       /
              /   .''               >::'  /
              `',:                 :    .'
                                   `:.:'
* @ File name --> b_keybroad.c
* @ Author    --> By@ LiuYu
* @ Version   --> V1.0
* @ Date      -->
* @ Brief     -->
* @           -->
*
* @ Copyright (C) 20**
* @ All rights reserved
*/

#include "../inc/b_mod_keybroad.h"
#if _KEYBROAD_ENABLE
#include "b_os.h"
#include "string.h"

/******************************************************************
 * @函数说明：   按键扫描进程
 * @输入参数：
 * @输出参数：   无
 * @返回参数：   void
 * @修改记录：   ----
 ******************************************************************/
void b_keybroad_Loop(void *argument)
{
    // b_log(" %d\r\n", bUtilGetTick());
    if (argument == NULL)
    {
        return;
    }

    b_keybroad_t *key_class = argument;

    uint8_t  i;
    uint16_t temp = 0;
#if _KEYBROAD_ALONE
    for (i = 0; i < key_class->nPortNumber; i++)
    {
        if (bHalGPIO_ReadPin(key_class->pPortTable[i].GPIOx, key_class->pPortTable[i].GPIO_Pin) ==
            key_class->pPortTable[i].eAvtivityState)
        {
            temp |= 1 << i;
        }
    }
#endif
#if _KEYBROAD_MATRIX
    uint8_t j;
    for (i = 0; i < key_class->unOutPortNumber; i++)
    {

        bHalGPIO_WritePin(key_class->pOutPortTable[i].GPIOx, key_class->pOutPortTable[i].GPIO_Pin,
                          key_class->pOutPortTable[i].eAvtivityState);  //一列输出
        uint8_t portV = bHalGPIO_Read(key_class->pInPortTable[0].GPIOx);
        for (j = 0; j < key_class->unInPortNumber; j++)
        {
            // if (bHalGPIO_ReadPin(key_class->pInPortTable[j].GPIOx,
            //                     key_class->pInPortTable[j].GPIO_Pin) ==
            //    key_class->pInPortTable[j].eAvtivityState)
            if ((portV & (1 << key_class->pInPortTable[j].GPIO_Pin)) > 0 ==
                key_class->pInPortTable[j].eAvtivityState)
            {
#if _KEYBROAD_ALONE
                temp |= 1 << ((i * key_class->unInPortNumber + j) + key_class->nPortNumber);
#else
                temp |= 1 << (i * key_class->unInPortNumber + j);
#endif
            }
        }
        bHalGPIO_WritePin(key_class->pOutPortTable[i].GPIOx, key_class->pOutPortTable[i].GPIO_Pin,
                          (uint8_t)!key_class->pOutPortTable[i].eAvtivityState);  //一列输出
    }
#endif

    key_class->DebounceCount += bSoftTimer_GetPeriod(&key_class->sTimer);

    if (key_class->SingleClickV != 0)
    {
        key_class->ValidFlag = 0;
    }

    if (temp != key_class->DebounceV)  //??3y???ˉ
    {
        // b_log("key bounce %d\r\n", temp);
        key_class->DebounceCount = 0;
        key_class->DebounceV     = temp;
        key_class->ValidFlag     = 0;
        key_class->PressTime     = 0;
        key_class->SingleClickV  = 0;
        key_class->LetGoV        = 0;
    }
    else if (key_class->DebounceCount > _KEYBROAD_DEBOUNCE_TIME)
    {
        if (key_class->ValidFlag == 0 || key_class->LetGoV != 0)  //°′?üóD±??ˉ
        {
            uint16_t letgo_temp;
            key_class->SingleClickV = temp & (temp ^ key_class->LongPressV);  //单机键值
            key_class->LongPressV   = temp;                                   //长按键值

            letgo_temp        = (~temp);
            key_class->LetGoV = letgo_temp & (letgo_temp ^ key_class->LongLetGoV);  //抬起键值
            key_class->LongLetGoV = letgo_temp;

            key_class->ValidFlag = 1;

            SIMPLE_EMIT(&key_class->hSignal, key_class);
            // b_log("key v %d\r\n", key_class->SingleClickV);
        }
        if (key_class->PressTime == 0)
        {
            key_class->PressTime = bUtilGetTick();
        }
        // key_class->PressTime = key_class->DebounceCount;  //按键时间
    }
    // b_log("%d\r\n", bUtilGetTick());
}

/******************************************************************
  * @函数说明：   按键扫描构造函数
  * @输入参数：   b_keybroad_io_t *pPinTable,  按键IO表
                  uint8_t nPinNumber        表数量
  * @输出参数：   无
  * @返回参数：   int
  * @修改记录：   ----
******************************************************************/
#if (_KEY_SCAN_MATRIX && _KEY_SCAN_ALONE)
int b_keybroad_Init(b_keybroad_t *hHnadle, const b_keybroad_io_t *pOutPortTable,
                    uint8_t unOutPortNumber, const b_keybroad_io_t *pInPortTable,
                    uint8_t unInPortNumber, const b_keybroad_io_t *pPortTable, uint8_t nPortNumber)
{
    if (hHnadle == NULL || pOutPortTable == NULL || pInPortTable == NULL || pPortTable == NULL)
    {
        return -1;
    }
    b_keybroad_t *key = hHnadle;

    memset(key, 0, sizeof(b_keybroad_t));

    key->pOutPortTable   = pOutPortTable;
    key->unOutPortNumber = unOutPortNumber;
    key->pInPortTable    = pInPortTable;
    key->unInPortNumber  = unInPortNumber;
    key->pPortTable      = pPortTable;
    key->nPortNumber     = nPortNumber;
    uint8_t i;
    for (i = 0; i < unOutPortNumber; i++)
    {
        bHalGPIO_Config(pOutPortTable[i].GPIOx, pOutPortTable[i].GPIO_Pin, B_HAL_GPIO_OUTPUT,
                        B_HAL_GPIO_PULLUP);
    }
    for (i = 0; i < unInPortNumber; i++)
    {
        bHalGPIO_Config(pInPortTable[i].GPIOx, pInPortTable[i].GPIO_Pin, B_HAL_GPIO_INPUT,
                        B_HAL_GPIO_PULLUP);
    }

    bSoftTimer_Init(&key->sTimer, 1, 5, b_keybroad_Loop, key);
    bSoftTimer_Start(&key->sTimer);
    return 0;
}

#elif _KEY_SCAN_MATRIX
int b_keybroad_Init(b_keybroad_t *hHnadle, const b_keybroad_io_t *pOutPortTable,
                    uint8_t unOutPortNumber, const b_keybroad_io_t *pInPortTable,
                    uint8_t unInPortNumber)
{
    if (hHnadle == NULL || pOutPortTable == NULL || pInPortTable == NULL)
    {
        return -1;
    }
    b_keybroad_t *key = hHnadle;
    uint8_t       i;

    memset(key, 0, sizeof(b_keybroad_t));

    key->pOutPortTable   = pOutPortTable;
    key->unOutPortNumber = unOutPortNumber;
    key->pInPortTable    = pInPortTable;
    key->unInPortNumber  = unInPortNumber;
    for (i = 0; i < unOutPortNumber; i++)
    {
        bHalGPIO_Config(pOutPortTable[i].GPIOx, pOutPortTable[i].GPIO_Pin, B_HAL_GPIO_OUTPUT,
                        B_HAL_GPIO_PULLUP);
    }
    for (i = 0; i < unInPortNumber; i++)
    {
        bHalGPIO_Config(pInPortTable[i].GPIOx, pInPortTable[i].GPIO_Pin, B_HAL_GPIO_INPUT,
                        B_HAL_GPIO_PULLUP);
    }
    bSoftTimer_Init(&key->sTimer, 1, 5, b_keybroad_Loop, key);
    bSoftTimer_Start(&key->sTimer);
    return 0;
}
#else
int b_keybroad_Init(b_keybroad_t *hHnadle, const b_keybroad_io_t *pPinTable, uint8_t nPinNumber)
{
    if (hHnadle == NULL || pPinTable == NULL || nPinNumber == 0)
    {
        return -1;
    }

    b_keybroad_t *key = hHnadle;

    memset(key, 0, sizeof(b_keybroad_t));

    key->pPortTable  = pPinTable;
    key->nPortNumber = nPinNumber;

    bSoftTimer_Init(&key->sTimer, SET, 5, b_keybroad_Loop, key);
    bSoftTimer_Start(&key->sTimer);
    return 0;
}
#endif

/******************************************************************
  * @函数说明：   获取按键的值
  * @输入参数：   b_keybroad_t *hHandle,  句柄
                  KEY_VALUE_TYPE_T eType      类型
  * @输出参数：   无
  * @返回参数：   uint32_t value
  * @修改记录：   ----
******************************************************************/
uint32_t b_keybroad_GetKeyValue(b_keybroad_t *hHandle, KEY_VALUE_TYPE_T eType)
{
    if (hHandle == NULL)
    {
        return 0;
    }
    b_keybroad_t *key    = hHandle;
    uint32_t      result = 0;
    switch (eType)
    {
        case KEY_VALUE_TYPE_CLICK_SINGLE:  //单击
        {
            result = key->SingleClickV;
        }
        break;
        case KEY_VALUE_TYPE_LET_GO:  //抬起
        {
            result = key->LetGoV;
        }
        break;
        case KEY_VALUE_TYPE_LONG_PRESS:  //长按
        {
            result = key->LongPressV;
        }
        break;
        case KEY_VALUE_TYPE_PRESS_TIME:  //按下时间
        {
            if (key->PressTime == 0)
            {
                result = 0;
            }
            else
            {
                result = bUtilGetTick() - key->PressTime;
            }
        }
        break;
        default:
            break;
    }
    return result;
}
/******************************************************************
  * @函数说明：   注册键值改变时的回调函数。 回调时的参数为按键句柄
  * @输入参数：   b_keybroad_t *hHandle, 句柄
                 IMPLE_SOLTS slots,         槽
                  void *pArg                回调时的参数
  * @输出参数：   无
  * @返回参数：   int
  * @修改记录：   ----
******************************************************************/
int b_keybroad_RegisterChangeCB(b_keybroad_t *hHandle, B_SOLTS_ITEM_T *solts, B_SOLTS solts_handle,
                                void *soltsArg)
{
    // CheckNULL(hHandle);
    b_keybroad_t *key = hHandle;

    b_signalsolts_connect(&key->hSignal, solts, solts_handle, soltsArg);

    return 0;
}

int b_keybroad_ExternalWrite(b_keybroad_t *hHandle, KEY_VALUE_TYPE_T eType, uint32_t unValue)
{
    if (hHandle == NULL)
    {
        return -1;
    }

    b_keybroad_t *key = hHandle;
    switch (eType)
    {
        case KEY_VALUE_TYPE_CLICK_SINGLE:  //单击
        {
            if ((key->SingleClickV & (~unValue)) != unValue)  //值变化
            {
                key->SingleClickV |= unValue;
                key->LongPressV |= unValue;
                key->LetGoV &= (~unValue);
                key->DebounceCount = 0;
                SIMPLE_EMIT(&key->hSignal, key);
            }
        }
        break;
        case KEY_VALUE_TYPE_LET_GO:  //抬起
        {
            if ((key->LetGoV & (~unValue)) != unValue)
            {
                key->LetGoV |= unValue;
                key->SingleClickV &= (~unValue);
                key->LongPressV &= (~unValue);
                key->DebounceCount = 0;
                SIMPLE_EMIT(&key->hSignal, key);
            }
        }
        break;

        default:
            return -1;
            // break;
    }

    return 0;
}
#endif